﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using caedisi.Views.Controls;
using System.Windows.Data;
using caedisi.Web.DataModel;
using caedisi.Models;
using caedisi.Views;
using caedisi.Controller;
using System.ComponentModel;
using System.Collections.Generic;


namespace caedisi.Helpers
{
    public class UIHelper
    {
        static int s = 0;
        static ComboBox cb = new ComboBox();
        static int rep = 0;
        public static int numberOfCa = 0;
        static int[,] mx = new int[50, 50];
        static List<VertexControl> listVertex = new List<VertexControl>();
        static List<CellularAutomata> listOfCa = new List<CellularAutomata>();
        static CellularAutomata cellular = new CellularAutomata();
        static int x1 = 0;
        static int x2 = 0;
        static int y1 = 0;
        static int y2 = 0;

        
        /// <summary>
        /// Generates the basic cell control.
        /// </summary>
        /// <param name="transitionRuleControl">The transition rule control.</param>
        /// <param name="xIndex">Index of the x.</param>
        /// <param name="yIndex">Index of the y.</param>
        /// <param name="zIndex">Index of the z.</param>
        /// <param name="bindingSource">The binding source.</param>
        /// <param name="bindingPath">The binding path.</param>
        /// <returns></returns>
        public static BasicCellControl GenerateBasicCellControl(Grid grid, int xIndex, int yIndex, int zIndex, object bindingSource, string bindingPath)
        {
            BasicCellControl newBasicCellControl = new BasicCellControl();
            grid.Children.Add(newBasicCellControl);
            Grid.SetRow(newBasicCellControl, xIndex);
            Grid.SetColumn(newBasicCellControl, yIndex);

            Binding b = new Binding()
            {
                Source = bindingSource,
                Path = new PropertyPath(bindingPath),
                Mode = BindingMode.TwoWay
            };
            newBasicCellControl.SetBinding(BasicCellControl.SelectedCellStateTypeIdEntityProperty, b);

            return newBasicCellControl;
        }


        /// <summary>
        /// Generates the vertex control.
        /// </summary>
        /// <param name="grid">The grid.</param>
        /// <param name="xIndex">Index of the x.</param>
        /// <param name="yIndex">Index of the y.</param>
        /// <param name="zIndex">Index of the z.</param>
        /// <param name="bindingSource">The binding source.</param>
        /// <param name="bindingPath">The binding path.</param>
        /// <returns></returns>
        public static HideVertexControl GenerateHiddenVertexControl(Grid grid, int xIndex, int yIndex, int zIndex, object bindingSource, string bindingPath)
        {
            HideVertexControl newVertexControl = new HideVertexControl();
            grid.Children.Add(newVertexControl);
            Grid.SetRow(newVertexControl, xIndex);
            Grid.SetColumn(newVertexControl, yIndex);

            Binding b = new Binding()
            {
                Source = bindingSource,
                Path = new PropertyPath(bindingPath),
                Mode = BindingMode.TwoWay
            };
            newVertexControl.SetBinding(HideVertexControl.SelectedCellStateTypeIdEntityProperty, b);

            return newVertexControl;
        }

        /// <summary>
        /// Generates the vertex control.
        /// </summary>
        /// <param name="grid">The grid.</param>
        /// <param name="xIndex">Index of the x.</param>
        /// <param name="yIndex">Index of the y.</param>
        /// <param name="zIndex">Index of the z.</param>
        /// <param name="bindingSource">The binding source.</param>
        /// <param name="bindingPath">The binding path.</param>
        /// <returns></returns>
        public static VertexControl GenerateVertexControl(Grid grid, int xIndex, int yIndex, int zIndex, object bindingSource, string bindingPath, int rows, int columns)
        {
            VertexControl newVertexControl = new VertexControl();

            //Add a label for direct access to vertex
            string chaine = "(" + xIndex.ToString() + "," + yIndex.ToString() + "," + zIndex.ToString() + ")";
            newVertexControl.Label = chaine;
            
            grid.Children.Add(newVertexControl);
            Grid.SetRow(newVertexControl, xIndex);
            Grid.SetColumn(newVertexControl, yIndex);

            Binding b = new Binding()
            {
                Source = bindingSource,
                Path = new PropertyPath(bindingPath),
                Mode = BindingMode.TwoWay
            };
            newVertexControl.SetBinding(VertexControl.SelectedCellStateTypeIdEntityProperty, b);

            return newVertexControl;
        }


        /// <summary>
        /// Constructs the grid cellular automata UI.
        /// </summary>
        public static void ConstructGridCellularAutomataUI(Grid gridCellularAutomata, Cell[, ,] cellularAutomataAsArray, GridLength columnWidthConfiguration, GridLength rowHeightConfiguration)
        {
            cb.Visibility = System.Windows.Visibility.Collapsed;

            gridCellularAutomata.RowDefinitions.Clear();
            gridCellularAutomata.ColumnDefinitions.Clear();
            //todo event ?? newVertex.MouseRightButtonDown -=

            int numberOfRows = cellularAutomataAsArray.GetLength(0);
            int numberOfColumns = cellularAutomataAsArray.GetLength(1);

            for (int i = 0; i < numberOfRows; i++)
            {
                RowDefinition rowDefinition = new RowDefinition();
                rowDefinition.Height = rowHeightConfiguration;
                gridCellularAutomata.RowDefinitions.Add(rowDefinition);
            }

            for (int i = 0; i < numberOfColumns; i++)
            {
                ColumnDefinition columnDefinition = new ColumnDefinition();
                columnDefinition.Width = columnWidthConfiguration;
                gridCellularAutomata.ColumnDefinitions.Add(columnDefinition);
            }

            //creating the cells
            for (int i = 0; i < numberOfRows; i++)
            {
                for (int j = 0; j < numberOfColumns; j++)
                {
                    int k = 0; //for now we only deal with 2D                       
                    VertexControl newVertex = UIHelper.GenerateVertexControl(gridCellularAutomata, i, j, k, cellularAutomataAsArray[i, j, k], "CellStateTypeId", numberOfRows, numberOfColumns);
                    newVertex.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(
                        (sender, e) =>
                        {
                            VertexControl vertexControl = sender as VertexControl;

                            BindingExpression bindingExpression = vertexControl.GetBindingExpression(VertexControl.SelectedCellStateTypeIdEntityProperty);
                            Cell cell = bindingExpression.DataItem as Cell;

                        }
                        );
                }
            }
        }

        /// <summary>
        /// Get the rep value
        /// </summary>
        /// <param name="x"></param>
        public static void SetRep(int x)
        {
            rep = x;
        }

        /// <summary>
        /// Constructs the subdivided grid cellular automata UI.
        /// </summary>
        /// <param name="list"></param>
        /// <param name="gridPartition"></param>
        /// <param name="gridCellularAutomata"></param>
        /// <param name="cellularAutomataAsArray"></param>
        /// <param name="columnWidthConfiguration"></param>
        /// <param name="rowHeightConfiguration"></param>
        /// <param name="tX"></param>
        /// <param name="tY"></param>
        /// <param name="ca"></param>
        public static void ConstructGridSubdividedCellularAutomata(List<CellularAutomata> list, Grid gridPartition, Grid gridSimulationInfo, Grid gridCellularAutomata, Cell[, ,] cellularAutomataAsArray, GridLength columnWidthConfiguration, GridLength rowHeightConfiguration, short[] tX, short[] tY, CellularAutomata ca, string parametersVisibility)
        {

            cellular = ca;
            listOfCa = new List<CellularAutomata>();
            numberOfCa = 0;
            cb = new ComboBox();
            cb.Items.Add("View Partitions Parameters");
            cb.SelectedItem = cb.Items[0];
            
            string label = "";
            string chaine = "";
            int index = 0;
            int combo = 0;
            
            gridCellularAutomata.RowDefinitions.Clear();
            gridCellularAutomata.ColumnDefinitions.Clear();
            //todo event ?? newVertex.MouseRightButtonDown -=

            int numberOfRows = cellularAutomataAsArray.GetLength(0);
            int numberOfColumns = cellularAutomataAsArray.GetLength(1);

            for (int i = 0; i < numberOfRows; i++)
            {
                RowDefinition rowDefinition = new RowDefinition();
                rowDefinition.Height = rowHeightConfiguration;
                gridCellularAutomata.RowDefinitions.Add(rowDefinition);
            }

            for (int i = 0; i < numberOfColumns; i++)
            {
                ColumnDefinition columnDefinition = new ColumnDefinition();
                columnDefinition.Width = columnWidthConfiguration;
                gridCellularAutomata.ColumnDefinitions.Add(columnDefinition);
            }
            for (int imx = 0; imx < numberOfRows; imx++)
            {
                for (int jmx = 0; jmx < numberOfColumns; jmx++)
                {
                    mx[imx, jmx] = 0;
                }
            }

            //creating the cells
            for (int i = 0; i < numberOfRows; i++)
            {
                for (int j = 0; j < numberOfColumns; j++)
                {
                    int k = 0; //for now we only deal with 2D                       
                    VertexControl newVertex = UIHelper.GenerateVertexControl(gridCellularAutomata, i, j, k, cellularAutomataAsArray[i, j, k], "CellStateTypeId", numberOfRows, numberOfColumns);
                    listVertex.Add(newVertex);

                    // Flag to indicate the beginning of subdivision
                    if (rep == 1)
                    {
                        newVertex.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(
                            (sender, e) =>
                            {
                                newVertex.innerEllipse.Height = 12;
                                newVertex.innerEllipse.Width = 12;
                                
                                VertexControl vertexControl = sender as VertexControl;

                                BindingExpression bindingExpression = vertexControl.GetBindingExpression(VertexControl.SelectedCellStateTypeIdEntityProperty);
                                Cell cell = bindingExpression.DataItem as Cell;

                                label = cell.Label;
                                
                                int maxX = 0;
                                int minX = 0;

                                int maxY = 0;
                                int minY = 0;


                                chaine += label;
                                String[] split = label.Split(',');
                                String[] splitX = split[0].Split('(');
                                short a = Convert.ToInt16(splitX[1]);
                                short b = Convert.ToInt16(split[1]);
                                if (mx[a, b] == 0)
                                {
                                    tX[s] = a;
                                    tY[s] = b;
                                    s++;
                                    index++;
                                }
                                else
                                {
                                    MessageBox.Show("Validation error, Wrong interval");
                                    newVertex.innerEllipse.Height = 20;
                                    newVertex.innerEllipse.Width = 20;
                                    index = 0;
                                }

                                if (index == 2)
                                {
                                    numberOfCa++;

                                    if (tY[s - 2] <= tY[s - 1])
                                    {
                                        minY = tY[s - 2];
                                        maxY = tY[s - 1];
                                    }
                                    else
                                    {
                                        minY = tY[s - 1];
                                        maxY = tY[s - 2];
                                    }

                                    if (tX[s - 2] <= tX[s - 1])
                                    {
                                        maxX = tX[s - 1];
                                        minX = tX[s - 2];
                                    }
                                    else
                                    {
                                        maxX = tX[s - 2];
                                        minX = tX[s - 1];
                                    }

                                    if ((minX == maxX) && (minY == maxY))
                                    {
                                        s = s - 2;
                                        numberOfCa--;
                                        MessageBox.Show("Operation cancelled");
                                    }
                                    else
                                    {
                                        bool test = true;
                                        for (int imx = minX; imx <= maxX; imx++)
                                        {
                                            for (int jmx = minY; jmx <= maxY; jmx++)
                                            {
                                                if (mx[imx, jmx] == 1)
                                                {
                                                    test = false;
                                                    MessageBox.Show("Validation error, Wrong interval");
                                                    jmx = maxY;
                                                    imx = maxX;
                                                    numberOfCa--;
                                                }
                                            }
                                        }
                                        if (test)
                                        {
                                            for (int kmx = minX; kmx <= maxX; kmx++)
                                            {
                                                for (int umx = minY; umx <= maxY; umx++)
                                                {
                                                    mx[kmx, umx] = 1;
                                                }
                                            }

                                            for (int iDesign = minX; iDesign <= maxX; iDesign++)
                                            {
                                                for (int jDesign = minY; jDesign <= maxY; jDesign++)
                                                {
                                                    int kDesign = 0;
                                                    string chaineDesign = "(" + iDesign.ToString() + "," + jDesign.ToString() + "," + kDesign.ToString() + ")";

                                                    foreach (VertexControl vertex in listVertex)
                                                    {
                                                        if (vertex.Label == chaineDesign)
                                                        {
                                                            vertex.innerEllipse.Width = 20;
                                                            vertex.innerEllipse.Height = 20;
                                                            vertex.textVertex.Text = numberOfCa.ToString();

                                                        }
                                                    }

                                                }
                                            }

                                            combo++;
                                            CellularAutomata newCA = new CellularAutomata();
                                            newCA.Height = (short)(maxX - minX + 1);
                                            newCA.Width = (short)(maxY - minY + 1);
                                            newCA.NeighbourhoodTypeId = ca.NeighbourhoodTypeId;
                                            newCA.Name = "Partition " + numberOfCa.ToString() + " of " + ca.Name;
                                            newCA.Description = ca.Description;
                                            newCA.RadiusContamination = ca.RadiusContamination;
                                            newCA.RadiusVisibility = ca.RadiusVisibility;
                                            listOfCa.Add(newCA);
                                            list.Add(newCA);
                                            createParameterButton(cb, numberOfCa, gridSimulationInfo, combo, parametersVisibility);

                                            x1 = minX;
                                            x2 = maxX;
                                            y1 = minY;
                                            y2 = maxY;

                                        }
                                        else
                                        {
                                            s = s - 2;
                                        }

                                    }

                                    index = 0;
                                }
                               
                            }
                            );


                        newVertex.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(
                        (senderrr, eee) =>
                        {
                            if (newVertex.innerEllipse.Height == 12)
                            {
                                newVertex.innerEllipse.Height = 9;
                                newVertex.innerEllipse.Width = 9;
                            }


                        }
                        );

                        newVertex.MouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(
                        (sender, e) =>
                        {
                            HideVertexControl vertexControl = sender as HideVertexControl;

                            BindingExpression bindingExpression = vertexControl.GetBindingExpression(HideVertexControl.SelectedCellStateTypeIdEntityProperty);
                            Cell cell = bindingExpression.DataItem as Cell;

                            VertexProperties vertexPropertiesWindow = new VertexProperties(cell);
                            vertexPropertiesWindow.Show();
                        }
                        );

                        // Set a flag to indicate the end of the table containing the subdivision border
                        for (int l = s; l < tX.Length; l++)
                        {
                            tX[l] = -1;
                        }

                    }
                }
            }
        }

        /// <summary>
        /// Define backButton fonction
        /// </summary>
        /// <param name="tX"></param>
        /// <param name="tY"></param>
        public static void backButton(short[] tX, short[] tY)
        {
            int minX, maxX, minY, maxY;

            if (tY[s - 2] < tY[s - 1])
            {
                minY = tY[s - 2];
                maxY = tY[s - 1];
            }
            else
            {
                minY = tY[s - 1];
                maxY = tY[s - 2];
            }

            if (tX[s - 2] < tX[s - 1])
            {
                maxX = tX[s - 1];
                minX = tX[s - 2];
            }
            else
            {
                maxX = tX[s - 2];
                minX = tX[s - 1];
            }

            for(int i = minX; i<=maxX; i++)
            {
                for (int j = minY; j <= maxY; j++)
                {
                    int k = 0;
                    mx[i, j] = 0;
                    string lb = "(" + i.ToString() + "," + j.ToString() + "," + k.ToString() + ")";
                    foreach (VertexControl vertex in listVertex)
                    {
                        if (vertex.Label == lb)
                        {
                            vertex.innerEllipse.Width = 12;
                            vertex.innerEllipse.Height = 12;
                            vertex.textVertex.Text = "";
                        }
                        
                    }
                }
            }
            cb.Items.Remove(cb.Items[numberOfCa]);
            numberOfCa--;
            s = s - 2;
        
        }



        /// <summary>
        /// Create the combobox for partition
        /// </summary>
        /// <param name="cb"></param>
        /// <param name="i"></param>
        /// <param name="gridPartition"></param>
        /// <param name="combo"></param>
        /// <param name="parametersVisibility"></param>
        public static void createParameterButton(ComboBox cb, int i, Grid gridPartition, int combo, string parametersVisibility)
        {
            if (combo == 1)
            {
                parametersVisibility = "collapsed";
                cb.Width = 222;
                cb.Height = 25;
                cb.HorizontalContentAlignment = HorizontalAlignment.Center;
                //cb.Background = new SolidColorBrush(Colors.Red);
                cb.VerticalAlignment = VerticalAlignment.Top;
                cb.HorizontalAlignment = HorizontalAlignment.Left;
                cb.Margin = new Thickness(0, 20, 0, 0);
                cb.SelectionChanged += ButtonEditCAParameters_Click;
                gridPartition.Children.Add(cb);
            }
            cb.Items.Add("Partition " + i.ToString() + " parameters");

        }

        /// <summary>
        /// Set parameters for each partition
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void ButtonEditCAParameters_Click(object sender, SelectionChangedEventArgs e)
        {
            CellularAutomataController controller = new CellularAutomataController();
            if (cb.SelectedIndex != 0)
            {
                //controller.CurrentEntity = listOfCa[cb.SelectedIndex - 1];
                CellularAutomataParameters editExistingCellularAutomataParametersWindow = new CellularAutomataParameters(listOfCa[cb.SelectedIndex - 1], Common.EnumCellularAutomataParametersEditMode.Edit);
                editExistingCellularAutomataParametersWindow.Show();
                editExistingCellularAutomataParametersWindow.Closed += new EventHandler(
                (o, ev) =>
                {
                    //controller.CurrentEntity = cellular;
                    cb.SelectedItem = cb.Items[0];
                }
                );
            }
        }

        static void EditExistingCellularAutomataParametersWindow_Closed(object sender, System.EventArgs e)
        {
            ;
        }


        /// <summary>
        /// Get recorded execution
        /// </summary>
        /// <param name="gridCellularAutomata"></param>
        /// <param name="cellularAutomataAsArray"></param>
        /// <param name="columnWidthConfiguration"></param>
        /// <param name="rowHeightConfiguration"></param>
        public static void ConstructGridRecordedCellularAutomataUI(Grid gridCellularAutomata, Cell[, ,] cellularAutomataAsArray, GridLength columnWidthConfiguration, GridLength rowHeightConfiguration)
        {
            //clear existing grid
            gridCellularAutomata.RowDefinitions.Clear();
            gridCellularAutomata.ColumnDefinitions.Clear();
            //todo event ?? newVertex.MouseRightButtonDown -=

            int numberOfRows = cellularAutomataAsArray.GetLength(0);
            int numberOfColumns = cellularAutomataAsArray.GetLength(1);

            for (int i = 1; i <= numberOfRows; i++)
            {
                RowDefinition rowDefinition = new RowDefinition();
                rowDefinition.Height = rowHeightConfiguration;
                gridCellularAutomata.RowDefinitions.Add(rowDefinition);
            }

            for (int i = 1; i <= numberOfColumns; i++)
            {
                ColumnDefinition columnDefinition = new ColumnDefinition();
                columnDefinition.Width = columnWidthConfiguration;
                gridCellularAutomata.ColumnDefinitions.Add(columnDefinition);
            }

            //creating the cells
            for (int i = 0; i < numberOfRows; i++)
            {
                for (int j = 0; j < numberOfColumns; j++)
                {
                    int k = 0; //for now we only deal with 2D                       
                    HideVertexControl newVertex = UIHelper.GenerateHiddenVertexControl(gridCellularAutomata, i, j, k, cellularAutomataAsArray[i, j, k], "CellStateTypeId");
                    
                }
            }
        }
    }
}
